home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / batchut / dat13c.zip / DAT.ASM next >
Encoding:
Assembly Source File  |  1994-03-08  |  34.7 KB  |  924 lines

  1. ;--------------------------------------------------------------------------;
  2. ;  Program:    DAT    .Asm                                                 ;
  3. ;  Purpose:    Displays current date and time.                             ;
  4. ;  Notes:      Compiles under TURBO Assembler, v3.0. Should work on any    ;
  5. ;                 machine running MS-DOS, v2.xx or higher.                 ;
  6. ;  Status:     Released into the public domain. Enjoy! If you use it,      ;
  7. ;                 let me know what you think. You don't have to send       ;
  8. ;                 any money, just comments and suggestions.                ;
  9. ;  Updates:    06-Mar-90, v1.0, GAT                                        ;
  10. ;                 - initial version.                                       ;
  11. ;              13-Mar-90, v1.1, GAT                                        ;
  12. ;                 - added n option to suppress final CR/LF sequence.       ;
  13. ;              19-Mar-90, GAT                                              ;
  14. ;                 - fixed up on-line help message.                         ;
  15. ;              22-Apr-90, v1.2, GAT                                        ;
  16. ;                 - revised most procedures based on work with ASK.        ;
  17. ;              05-May-90, GAT                                              ;
  18. ;                 - fixed bug in handling of non-zero return codes.        ;
  19. ;              12-Jun-90, GAT                                              ;
  20. ;                 - fixed bug in conv_Int2Ascii wrt DI's final value.      ;
  21. ;              08-Jul-90, GAT                                              ;
  22. ;                 - added macros to push/pop registers.                    ;
  23. ;              28-Aug-90, v1.3a, GAT                                       ;
  24. ;                 - put equates and macros in separate files.              ;
  25. ;                 - put common routines in libs.                           ;
  26. ;                 - added equates for date/time separators.                ;
  27. ;              12-Oct-91, v1.3b, GAT                                       ;
  28. ;                 - revised include file names.                            ;
  29. ;                 - replaced references to Push_M and Pop_M macros with    ;
  30. ;                    calls to push and pop.                                ;
  31. ;                 - removed local stack: it's not necessary.               ;
  32. ;              03-Jul-93, v1.3c, GAT                                       ;
  33. ;                 - compiled with TASM v3.0.                               ;
  34. ;                 - version number now comes from makefile.                ;
  35. ;                 - specified ??date in lowercase.                         ;
  36. ;--------------------------------------------------------------------------;
  37.  
  38. ;--------------------------------------------------------------------------;
  39. ;  Author:     George A. Theall                                            ;
  40. ;  SnailMail:  TifaWARE                                                    ;
  41. ;              610 South 48th St                                           ;
  42. ;              Philadelphia, PA.  19143                                    ;
  43. ;              U.S.A.                                                      ;
  44. ;  E-Mail:     george@tifaware.com                                         ;
  45. ;              theall@popmail.tju.edu                                      ;
  46. ;              theall@mcneil.sas.upenn.edu                                 ;
  47. ;              george.theall@satalink.com                                  ;
  48. ;--------------------------------------------------------------------------;
  49.  
  50. ;--------------------------------------------------------------------------;
  51. ;                          D I R E C T I V E S                             ;
  52. ;--------------------------------------------------------------------------;
  53. DOSSEG
  54. MODEL     tiny
  55.  
  56. IDEAL
  57. LOCALS
  58. JUMPS
  59.  
  60. FALSE               EQU       0
  61. TRUE                EQU       NOT FALSE
  62. BELL                EQU       7
  63. BS                  EQU       8
  64. TAB                 EQU       9
  65. CR                  EQU       13
  66. LF                  EQU       10
  67. ESCAPE              EQU       27             ; nb: ESC is a TASM keyword
  68. SPACE               EQU       ' '
  69. KEY_F1              EQU       3bh
  70. KEY_F2              EQU       3ch
  71. KEY_F3              EQU       3dh
  72. KEY_F4              EQU       3eh
  73. KEY_F5              EQU       3fh
  74. KEY_F6              EQU       40h
  75. KEY_F7              EQU       41h
  76. KEY_F8              EQU       42h
  77. KEY_F9              EQU       43h
  78. KEY_F10             EQU       44h
  79. KEY_HOME            EQU       47h
  80. KEY_UP              EQU       48h
  81. KEY_PGUP            EQU       49h
  82. KEY_LEFT            EQU       4bh
  83. KEY_RIGHT           EQU       4dh
  84. KEY_END             EQU       4fh
  85. KEY_DOWN            EQU       50h
  86. KEY_PGDN            EQU       51h
  87. KEY_INS             EQU       52h
  88. KEY_DEL             EQU       53h
  89. KEY_C_F1            EQU       5eh
  90. KEY_C_F2            EQU       5fh
  91. KEY_C_F3            EQU       60h
  92. KEY_C_F4            EQU       61h
  93. KEY_C_F5            EQU       62h
  94. KEY_C_F6            EQU       63h
  95. KEY_C_F7            EQU       64h
  96. KEY_C_F8            EQU       65h
  97. KEY_C_F9            EQU       66h
  98. KEY_C_F10           EQU       67h
  99. KEY_C_LEFT          EQU       73h
  100. KEY_C_RIGHT         EQU       74h
  101. KEY_C_END           EQU       75h
  102. KEY_C_PGDN          EQU       76h
  103. KEY_C_HOME          EQU       77h
  104. KEY_C_PGUP          EQU       84h
  105. KEY_F11             EQU       85h
  106. KEY_F12             EQU       86h
  107. KEY_C_F11           EQU       89h
  108. KEY_C_F12           EQU       8ah
  109. @16BIT              EQU       (@Cpu AND 8) EQ 0
  110. @32BIT              EQU       (@Cpu AND 8)
  111. NOWARN RES
  112. MACRO    PUSHA                               ;; Pushs all registers
  113.    IF @Cpu AND 2                             ;;  if for 80186 or better
  114.       pusha                                  ;;   use regular opcode
  115.    ELSE                                      ;;  else
  116.       push ax cx dx bx sp bp si di           ;;   nb: order matters!
  117.                                              ;;   nb: SP is not original!
  118.    ENDIF
  119. ENDM
  120. MACRO    POPA                                ;; Pops all registers
  121.    IF @Cpu AND 2                             ;;  if for 80186 or better
  122.       popa                                   ;;   use regular opcode
  123.    ELSE                                      ;;  else
  124.       pop di si bp bx bx dx cx ax            ;;   nb: order matters!
  125.                                              ;;   nb: don't pop SP!
  126.    ENDIF
  127. ENDM
  128. NOWARN RES
  129. MACRO    ZERO     RegList                    ;; Zeros registers
  130.    IRP      Reg, <RegList>
  131.          xor      Reg, Reg
  132.    ENDM
  133. ENDM
  134.  
  135. DOS                 EQU       21h            ; main MSDOS interrupt
  136. STDIN               EQU       0              ; standard input
  137. STDOUT              EQU       1              ; standard output
  138. STDERR              EQU       2              ; error output
  139. STDAUX              EQU       3              ; COM port
  140. STDPRN              EQU       4              ; printer
  141. TSRMAGIC            EQU       424bh          ; magic number
  142. STRUC     ISR
  143.           Entry     DW        10EBh          ; short jump ahead 16 bytes
  144.           OldISR    DD        ?              ; next ISR in chain
  145.           Sig       DW        TSRMAGIC       ; magic number
  146.           EOIFlag   DB        ?              ; 0 (80) if soft(hard)ware int
  147.           Reset     DW        ?              ; short jump to hardware reset
  148.           Reserved  DB        7 dup (0)
  149. ENDS
  150. STRUC     ISRHOOK
  151.           Vector    DB        ?              ; vector hooked
  152.           Entry     DW        ?              ; offset of TSR entry point
  153. ENDS
  154. STRUC     TSRSIG
  155.           Company   DB        8 dup (" ")    ; blank-padded company name
  156.           Product   DB        8 dup (" ")    ; blank-padded product name
  157.           Desc      DB        64 dup (0)     ; ASCIIZ product description
  158. ENDS
  159. GLOBAL at : PROC
  160. GLOBAL errmsg : PROC
  161.    GLOBAL ProgName : BYTE                    ; needed for errmsg()
  162.    GLOBAL EOL : BYTE                         ; ditto
  163. GLOBAL fgetc : PROC
  164. GLOBAL fputc : PROC
  165. GLOBAL fputs : PROC
  166. GLOBAL getchar : PROC
  167. GLOBAL getdate : PROC
  168. GLOBAL getswtch : PROC
  169. GLOBAL gettime : PROC
  170. GLOBAL getvdos : PROC
  171. GLOBAL getvect : PROC
  172. GLOBAL isatty : PROC
  173. GLOBAL kbhit : PROC
  174. GLOBAL pause : PROC
  175. GLOBAL putchar : PROC
  176. GLOBAL setvect : PROC
  177. GLOBAL sleep : PROC
  178. GLOBAL find_NextISR : PROC
  179. GLOBAL find_PrevISR : PROC
  180. GLOBAL hook_ISR : PROC
  181. GLOBAL unhook_ISR : PROC
  182. GLOBAL free_Env : PROC
  183. GLOBAL fake_Env : PROC
  184. GLOBAL check_ifInstalled : PROC
  185. GLOBAL install_TSR : PROC
  186. GLOBAL remove_TSR : PROC
  187.  
  188. GLOBAL atoi : PROC
  189. GLOBAL atou : PROC
  190. GLOBAL utoa : PROC
  191.  
  192. EOS                 EQU       0              ; terminates strings
  193. GLOBAL isalpha : PROC
  194. GLOBAL isdigit : PROC
  195. GLOBAL islower : PROC
  196. GLOBAL isupper : PROC
  197. GLOBAL iswhite : PROC
  198. GLOBAL memcmp : PROC
  199. GLOBAL strchr : PROC
  200. GLOBAL strcmp : PROC
  201. GLOBAL strlen : PROC
  202. GLOBAL tolower : PROC
  203. GLOBAL toupper : PROC
  204.  
  205.  
  206. ERRH      equ       1                        ; errorlevel if help given
  207. DATE_SEP  equ       '/'                      ; date separator
  208. TIME_SEP  equ       ':'                      ; time separator
  209.  
  210.  
  211. ;--------------------------------------------------------------------------;
  212. ;                        C O D E    S E G M E N T                          ;
  213. ;--------------------------------------------------------------------------;
  214. CODESEG
  215.  
  216. ORG       80h                                ; commandline
  217. LABEL     CmdLen    BYTE
  218.           db        ?
  219. LABEL     CmdLine   BYTE
  220.           db        127 dup (?)
  221.  
  222. ORG       100h                               ; start of .COM file
  223. STARTUPCODE
  224.           jmp       main                     ; skip over data and stack
  225.  
  226. ;--------------------------------------------------------------------------;
  227. ;                               D A T A                                    ;
  228. ;--------------------------------------------------------------------------;
  229. LABEL     ProgName  BYTE
  230.           db        'dat: ', EOS
  231. LABEL     EOL       BYTE
  232.           db        '.', CR, LF, EOS
  233. LABEL     HelpMsg   BYTE
  234.           db        CR, LF
  235.           db        'TifaWARE DAT, v', VERS_STR, ', ', ??date
  236.           db        ' - displays the current date and time.', CR, LF
  237.           db        'Usage: dat [-options] [msg]', CR, LF, LF
  238.           db        'Options:', CR, LF
  239.           db        '  -d = display date', CR, LF
  240.           db        '  -n = suppress final newline sequence', CR, LF
  241.           db        '  -t = display time', CR, LF
  242.           db        '  -? = display this help message', CR, LF, LF
  243.           db        'msg is an optional message to display before '
  244.           db        'the date or time.', CR, LF, EOS
  245. LABEL     Err1Msg   BYTE
  246.           db        'illegal option -- '
  247. LABEL     OptCh     BYTE
  248.           db        ?
  249.           db        EOS
  250. LABEL     TwoDigits BYTE                     ; space for two digits
  251.           db        2 dup (?), EOS
  252.  
  253. SwitCh    db        '-'                      ; char introducing options
  254. HFlag     db        0                        ; flag for on-line help
  255. DFlag     db        0                        ; flag for displaying date
  256. NFlag     db        0                        ; flag for suppressing CR/LF
  257. TFlag     db        0                        ; flag for displaying time
  258. MsgLen    db        0                        ; length of message text
  259. MsgTxt    dw        ?                        ; near pointer to message text
  260. RCode     db        0                        ; program return code
  261.  
  262.  
  263. ;--------------------------------------------------------------------------;
  264. ;                           P R O C E D U R E S                            ;
  265. ;--------------------------------------------------------------------------;
  266. ;----  put_TwoDigits  -----------------------------------------------------;
  267. ;  Purpose:    Displays a number between 0 and 99 on STDOUT with a leading ;
  268. ;                   0 as necessary.                                        ;
  269. ;  Notes:      No validity checks are done.                                ;
  270. ;  Entry:      AL = number to display.                                     ;
  271. ;  Exit:       n/a                                                         ;
  272. ;  Calls:      utoa, putchar, fputs                                        ;
  273. ;  Changes:    [TwoDigits]                                                 ;
  274. ;--------------------------------------------------------------------------;
  275. PROC put_TwoDigits
  276.  
  277.           push      ax bx dx di
  278.           ZERO      ah
  279.           mov       bx, STDOUT
  280.           mov       di, OFFSET TwoDigits
  281.           call      utoa                     ; treat it as unsigned int
  282.           cmp       al, 9                    ; need a leading 0?
  283.           ja        SHORT @@WriteIt
  284.           mov       dl, '0'
  285.           call      putchar
  286. @@WriteIt:
  287.           mov       dx, di
  288.           call      fputs
  289.           pop       di dx bx ax
  290.  
  291.           ret
  292. ENDP put_TwoDigits
  293.  
  294.  
  295. ;----  skip_Spaces  -------------------------------------------------------;
  296. ;  Purpose:    Skips past spaces in a string.                              ;
  297. ;  Notes:      Scanning stops with either a non-space *OR* CX = 0.         ;
  298. ;  Entry:      DS:SI = start of string to scan.                            ;
  299. ;  Exit:       AL = next non-space character,                              ;
  300. ;              CX is adjusted as necessary,                                ;
  301. ;              DS:SI = pointer to next non-space.                          ;
  302. ;  Calls:      none                                                        ;
  303. ;  Changes:    AL, CX, SI                                                  ;
  304. ;--------------------------------------------------------------------------;
  305. PROC skip_Spaces
  306.  
  307.           jcxz      SHORT @@Fin
  308. @@NextCh:
  309.           lodsb
  310.           cmp       al, ' '
  311.           loopz     @@NextCh
  312.           jz        SHORT @@Fin              ; CX = 0; don't adjust
  313.  
  314.           inc       cx                       ; adjust counters if cx > 0
  315.           dec       si
  316.  
  317. @@Fin:
  318.           ret
  319. ENDP skip_Spaces
  320.  
  321.  
  322. ;----  get_Opt  -----------------------------------------------------------;
  323. ;  Purpose:    Get a commandline option.                                   ;
  324. ;  Notes:      none                                                        ;
  325. ;  Entry:      AL = option character,                                      ;
  326. ;  Exit:       n/a                                                         ;
  327. ;  Calls:      tolower, errmsg                                             ;
  328. ;  Changes:    AX, DX,                                                     ;
  329. ;              [OptCh], [HFlag], [DFlag], [NFlag], [TFlag],                ;
  330. ;--------------------------------------------------------------------------;
  331. PROC get_Opt
  332.  
  333.           mov       [OptCh], al              ; save for later
  334.           call      tolower                  ; use only lowercase in cmp.
  335.           cmp       al, 'd'
  336.           jz        SHORT @@OptD
  337.           cmp       al, 'n'
  338.           jz        SHORT @@OptN
  339.           cmp       al, 't'
  340.           jz        SHORT @@OptT
  341.           cmp       al, '?'
  342.           jz        SHORT @@OptH
  343.           mov       dx, OFFSET Err1Msg       ; unrecognized option
  344.           call      errmsg                   ; then *** DROP THRU *** to OptH
  345.  
  346. ;
  347. ; Various possible options.
  348. ;
  349. @@OptH:
  350.           mov       [HFlag], 1               ; set help flag
  351.           jmp       SHORT @@Fin
  352.  
  353. @@OptD:
  354.           mov       [DFlag], 1               ; display date
  355.           jmp       SHORT @@Fin
  356.  
  357. @@OptN:
  358.           mov       [NFlag], 1               ; no final CR/LF
  359.           jmp       SHORT @@Fin
  360.  
  361. @@OptT:
  362.           mov       [TFlag], 1               ; display time
  363.  
  364. @@Fin:
  365.           ret
  366. ENDP get_Opt
  367.  
  368.  
  369. ;----  get_Arg  -----------------------------------------------------------;
  370. ;  Purpose:    Gets a non-option from the set of commandline arguments.    ;
  371. ;  Notes:      Anything left on the commandline is user's message text.    ;
  372. ;  Entry:      CX = count of characters left in commandline,               ;
  373. ;              DS:SI = pointer to argument to process.                     ;
  374. ;  Exit:       CX = zero                                                   ;
  375. ;              DS:SI = points to CR after commandline.                     ;
  376. ;  Calls:      none                                                        ;
  377. ;  Changes:    CX, SI                                                      ;
  378. ;              [MsgLen], [MsgTxt]                                          ;
  379. ;--------------------------------------------------------------------------;
  380. PROC get_Arg
  381.  
  382.           mov       [MsgLen], cl             ; for safekeeping
  383.           mov       [MsgTxt], si
  384.           add       si, cx                   ; adjust so nothing's left
  385.           ZERO      cl
  386.           mov       [BYTE PTR si], EOS       ; finish off string
  387.  
  388.           ret
  389. ENDP get_Arg
  390.  
  391.  
  392. ;----  process_CmdLine  ---------------------------------------------------;
  393. ;  Purpose:    Processes commandline arguments.                            ;
  394. ;  Notes:      A switch character by itself is ignored.                    ;
  395. ;              No arguments whatsoever causes help flag to be set.         ;
  396. ;  Entry:      n/a                                                         ;
  397. ;  Exit:       n/a                                                         ;
  398. ;  Calls:      skip_Spaces, get_Opt, get_Arg                               ;
  399. ;  Changes:    AX, CX, SI,                                                 ;
  400. ;              DX (get_Opt),                                               ;
  401. ;              [DFlag], [TFlag],                                           ;
  402. ;              [OptCh], [NFlag] (get_Opt),                                 ;
  403. ;              [MsgLen], [MsgTxt] (get_Arg),                               ;
  404. ;              Direction flag is cleared.                                  ;
  405. ;--------------------------------------------------------------------------;
  406. PROC process_CmdLine
  407.  
  408.           cld                                ; forward, march!
  409.           ZERO      ch
  410.           mov       cl, [CmdLen]             ; length of commandline
  411.           mov       si, OFFSET CmdLine       ; offset to start of commandline
  412.  
  413.           call      skip_Spaces              ; check if any args supplied
  414.           or        cl, cl
  415.           jnz       SHORT @@ArgLoop          ;   yep
  416.           mov       [DFlag], 1               ;   nope, so display date ...
  417.           mov       [TFlag], 1               ;     and time
  418.           jmp       SHORT @@Fin
  419.  
  420. ;
  421. ; For each blank-delineated argument on the commandline...
  422. ;
  423. @@ArgLoop:
  424.           lodsb                              ; next character
  425.           dec       cl
  426.           cmp       al, [SwitCh]             ; is it the switch character?
  427.           jnz       SHORT @@NonOpt           ;   no
  428.  
  429. ;
  430. ; Isolate each option and process it. Stop when a space is reached.
  431. ;
  432. @@OptLoop:
  433.           jcxz      SHORT @@Fin              ; abort if nothing left
  434.           lodsb
  435.           dec       cl
  436.           cmp       al, ' '
  437.           jz        SHORT @@NextArg          ; abort when space reached
  438.           call      get_Opt
  439.           jmp       @@OptLoop
  440.  
  441. ;
  442. ; Process the current argument, which is *not* an option.
  443. ; Then, *drop thru* to advance to next argument.
  444. ;
  445. @@NonOpt:
  446.           dec       si                       ; back up one character
  447.           inc       cl
  448.           call      get_Arg
  449.  
  450. ;
  451. ; Skip over spaces until next argument is reached.
  452. ;
  453. @@NextArg:
  454.           call      skip_Spaces
  455.           or        cl, cl
  456.           jnz       @@ArgLoop
  457.  
  458. @@Fin:
  459.           ret
  460. ENDP process_CmdLine
  461.  
  462.  
  463. ;--------------------------------------------------------------------------;
  464. ;                         E N T R Y   P O I N T                            ;
  465. ;--------------------------------------------------------------------------;
  466. ;----  main  --------------------------------------------------------------;
  467. ;  Purpose:    Main section of program.                                    ;
  468. ;  Notes:      none                                                        ;
  469. ;  Entry:      Arguments as desired                                        ;
  470. ;  Exit:       Return code as follows:                                     ;
  471. ;                   0 => program ran successfully                          ;
  472. ;                   1 => on-line help requested                            ;
  473. ;  Calls:      process_CmdLine, fputs, putchar, getdate, put_TwoDigits,    ;
  474. ;                   gettime                                                ;
  475. ;  Changes:    n/a                                                         ;
  476. ;--------------------------------------------------------------------------;
  477. main:
  478.  
  479. ;
  480. ; Process commandline arguments. If the variable HFlag is set, then
  481. ; on-line help is displayed and the program immediately terminates.
  482. ;
  483.           call      process_CmdLine          ; process commandline args
  484.  
  485.           cmp       [HFlag], 0               ; is help needed?
  486.           jz        SHORT @@NoHelp           ;   no
  487.           mov       [RCode], ERRH            ;   yes, so set return code
  488.           mov       bx, STDERR
  489.           mov       dx, OFFSET HelpMsg       ;     point to help message
  490.           call      fputs                    ;     display it
  491.           jmp       SHORT @@Fin              ;     and jump to end of program
  492.  
  493. ;
  494. ; Display any message from commandline then get keypress from user.
  495. ;
  496. @@NoHelp:
  497.           mov       bx, STDOUT               ; everything to stdout
  498.           cmp       [MsgLen], 0              ; anything to print out?
  499.           jz        SHORT @@Date?            ;   nope
  500.           mov       dx, [MsgTxt]             ; display message text
  501.           call      fputs
  502.           mov       dl, ' '                  ; and a space
  503.           call      putchar
  504.  
  505. @@Date?:
  506.           cmp       [DFlag], 0
  507.           jz        SHORT @@Time?
  508.  
  509.           call      getdate
  510.           mov       al, dh                   ; dh = month
  511.           call      put_TwoDigits
  512.           mov       al, dl                   ; dl = day
  513.           mov       dl, DATE_SEP             ; now we can use dl for DATE_SEP
  514.           call      putchar
  515.           call      put_TwoDigits
  516.           call      putchar                  ; dl still holds DATE_SEP
  517.           mov       ax, cx                   ; cx = year
  518.           sub       ax, 1900                 ; assume 20th century
  519.           call      put_TwoDigits
  520.           mov       dl, ' '
  521.           call      putchar
  522.  
  523. @@Time?:
  524.           cmp       [TFlag], 0               ; display time?
  525.           jz        SHORT @@FinalEOL?        ;   no
  526.  
  527.           call      gettime
  528.           mov       al, ch                   ; ch = hour
  529.           call      put_TwoDigits
  530.           mov       dl, TIME_SEP
  531.           call      putchar
  532.           mov       al, cl                   ; cl = minutes
  533.           call      put_TwoDigits
  534.  
  535. @@FinalEOL?:
  536.           cmp       [NFlag], 0               ; suppress final CR/LF?
  537.           jnz       SHORT @@Fin              ;   no
  538.  
  539.           mov       dx, OFFSET EOL+1
  540.           call      fputs
  541.  
  542. ;
  543. ; Ok, let's terminate the program and exit with proper return code.
  544. ;
  545. @@Fin:
  546.           mov       al, [RCode]
  547.           mov       ah, 4ch
  548.           int       DOS
  549.  
  550. EVEN
  551. Buffer   db    ?                          ; space for single character
  552.                                           ; nb: shared by fgetc() & fputc()
  553.  
  554.  
  555. ;-------------------------------------------------------------------------;
  556. ;  Purpose:    Reads a character from specified device.
  557. ;  Notes:      No checks are done on BX's validity.
  558. ;              Buffer is shared by fputc(). Do *NOT* use in a 
  559. ;                 multitasking environment like DESQview.
  560. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  561. ;  Entry:      BX = device handle.
  562. ;  Exit:       AL = character,
  563. ;              Carry flag set on error (AX holds error code).
  564. ;  Calls:      none
  565. ;  Changes:    AX
  566. ;              flags
  567. ;-------------------------------------------------------------------------;
  568. PROC fgetc
  569.  
  570.    push     cx dx
  571. IF @DataSize NE 0
  572.    push     ds
  573.    mov      ax, @data
  574.    mov      ds, ax
  575. ENDIF
  576.  
  577.    mov      dx, OFFSET Buffer             ; point to storage
  578.    mov      cx, 1                         ; only need 1 char
  579.    mov      ah, 3fh
  580.    int      DOS                           ; get it
  581.    jc       SHORT @@Fin                   ; abort on error
  582.    mov      al, [Buffer]
  583.  
  584. @@Fin:
  585. IF @DataSize NE 0
  586.    pop      ds
  587. ENDIF
  588.    pop      dx cx
  589.    ret
  590.  
  591. ENDP fgetc
  592.  
  593.  
  594. ;-------------------------------------------------------------------------;
  595. ;  Purpose:    Writes a character to specified device.
  596. ;  Notes:      No checks are done on BX's validity.
  597. ;              Buffer is shared by fputc(). Do *NOT* use in a 
  598. ;                 multitasking environment like DESQview.
  599. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  600. ;  Entry:      AL = character to display,
  601. ;              BX = device handle.
  602. ;  Exit:       AL = 1 if successful,
  603. ;              Carry flag set on error (AX holds error code).
  604. ;  Calls:      none
  605. ;  Changes:    AX
  606. ;-------------------------------------------------------------------------;
  607. PROC fputc
  608.  
  609.    push     cx dx
  610. IF @DataSize NE 0
  611.    push     ds
  612.    mov      dx, @data
  613.    mov      ds, ax
  614. ENDIF
  615.  
  616.    mov      dx, OFFSET Buffer             ; point to storage
  617.    mov      [Buffer], al                  ; save char
  618.    mov      cx, 1                         ; only write 1 char
  619.    mov      ah, 40h
  620.    int      DOS
  621.  
  622. IF @DataSize NE 0
  623.    pop      ds
  624. ENDIF
  625.    pop      dx cx
  626.    ret
  627.  
  628. ENDP fputc
  629.  
  630.  
  631. ;-------------------------------------------------------------------------;
  632. ;  Purpose:    Reads a character from STDIN.
  633. ;  Notes:      Character is echoed to display.
  634. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  635. ;  Entry:      n/a
  636. ;  Exit:       AL = character.
  637. ;  Calls:      none
  638. ;  Changes:    AX
  639. ;-------------------------------------------------------------------------;
  640. PROC getchar
  641.  
  642.    mov      ah, 1
  643.    int      DOS
  644.    ret
  645.  
  646. ENDP getchar
  647.  
  648.  
  649. ;-------------------------------------------------------------------------;
  650. ;  Purpose:    Writes a character to STDOUT device.
  651. ;  Notes:      none
  652. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  653. ;  Entry:      DL = character to display.
  654. ;  Exit:       n/a
  655. ;  Calls:      none
  656. ;  Changes:    none
  657. ;-------------------------------------------------------------------------;
  658. PROC putchar
  659.  
  660.    push     ax
  661.    mov      ah, 2
  662.    int      DOS
  663.    pop      ax
  664.    ret
  665.  
  666. ENDP putchar
  667.  
  668.  
  669. ;-------------------------------------------------------------------------;
  670. ;  Purpose:    Checks if a character is ready for input from STDIN.
  671. ;  Notes:      none
  672. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  673. ;  Entry:      n/a
  674. ;  Exit:       zf = 1 if character available.
  675. ;  Calls:      none
  676. ;  Changes:    flags
  677. ;-------------------------------------------------------------------------;
  678. PROC kbhit
  679.  
  680.    push     ax
  681.    mov      ah, 0bh
  682.    int      DOS
  683.    cmp      al, 0ffh                      ; AL = FFh if character ready
  684.    pop      ax
  685.    ret
  686.  
  687. ENDP kbhit
  688.  
  689.  
  690. EVEN
  691. ;-------------------------------------------------------------------------;
  692. ;  Purpose:    Writes an ASCIIZ string to specified device.
  693. ;  Notes:      A zero-length string doesn't seem to cause problems when
  694. ;                 this output function is used.
  695. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  696. ;  Entry:      BX = device handle,
  697. ;              DS:DX = pointer to string.
  698. ;  Exit:       Carry flag set if EOS wasn't found or handle is invalid.
  699. ;  Calls:      strlen
  700. ;  Changes:    none
  701. ;-------------------------------------------------------------------------;
  702. PROC fputs
  703.  
  704.    push     ax cx di es
  705.    mov      ax, ds
  706.    mov      es, ax
  707.    mov      di, dx
  708.    call     strlen                        ; set CX = length of string
  709.    jc       SHORT @@Fin                   ; abort if problem finding end
  710.    mov      ah, 40h                       ; MS-DOS raw output function
  711.    int      DOS
  712. @@Fin:
  713.    pop      es di cx ax
  714.    ret
  715.  
  716. ENDP fputs
  717.  
  718.  
  719. EVEN
  720. ;-------------------------------------------------------------------------;
  721. ;  Purpose:    Writes an error message to stderr.
  722. ;  Notes:      none
  723. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  724. ;  Entry:      DS:DX = pointer to error message.
  725. ;  Exit:       n/a
  726. ;  Calls:      fputs
  727. ;  Changes:    none
  728. ;-------------------------------------------------------------------------;
  729. PROC errmsg
  730.  
  731.    push     bx dx
  732.    mov      bx, STDERR
  733.    mov      dx, OFFSET ProgName           ; display program name
  734.    call     fputs
  735.    pop      dx                            ; recover calling parameters
  736.    push     dx                            ; and save again to avoid change
  737.    call     fputs                         ; display error message
  738.    mov      dx, OFFSET EOL
  739.    call     fputs
  740.    pop      dx bx
  741.    ret
  742.  
  743. ENDP errmsg
  744.  
  745.  
  746. EVEN
  747. ;-------------------------------------------------------------------------;
  748. ;  Purpose:    Gets current system date, based on DOS's internal clock.
  749. ;  Notes:      none
  750. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  751. ;  Entry:      n/a
  752. ;  Exit:       AL = day of week (0 = Sunday)
  753. ;              DL = day (1 to 31)
  754. ;              DH = month (1 to 12)
  755. ;              CX = year (1980 to 2099)
  756. ;  Calls:      none
  757. ;  Changes:    AX, CX, DX
  758. ;-------------------------------------------------------------------------;
  759. PROC getdate
  760.  
  761.    mov      ah, 2ah                       ; MS-DOS get system date function
  762.    int      DOS
  763.    ret
  764.  
  765. ENDP getdate
  766.  
  767.  
  768. ;-------------------------------------------------------------------------;
  769. ;  Purpose:    Gets current system time, based on DOS's internal clock.
  770. ;  Notes:      none
  771. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  772. ;  Entry:      n/a
  773. ;  Exit:       CL = minutes (0 - 59)
  774. ;              CH = hour (0 - 23)
  775. ;              DL = hundredths of seconds (0 - 99)
  776. ;              DH = seconds (0 - 59)
  777. ;  Calls:      none
  778. ;  Changes:    CX, DX
  779. ;-------------------------------------------------------------------------;
  780. PROC gettime
  781.  
  782.    push     ax
  783.    mov      ah, 2ch                       ; MS-DOS get system time function
  784.    int      DOS
  785.    pop      ax
  786.    ret
  787.  
  788. ENDP gettime
  789.  
  790.  
  791. EVEN
  792. ;-------------------------------------------------------------------------;
  793. ;  Purpose:    Converts an *unsigned* integer in range [0, 65535] to
  794. ;              an ASCIIZ string of digits.
  795. ;  Notes:      No checks are made to ensure storage area is big enough.
  796. ;              A terminating null is added.
  797. ;  Requires:   8086-class CPU.
  798. ;  Entry:      AX = unsigned integer value,
  799. ;              ES:DI = pointer to string storage area.
  800. ;  Exit:       ES:DI = pointer to start of string.
  801. ;  Calls:      none
  802. ;  Changes:    DI
  803. ;-------------------------------------------------------------------------;
  804. PROC utoa
  805.  
  806.    push     ax bx cx dx di
  807.    mov      bx, 10                        ; conversion factor
  808.    ZERO     cx                            ; track # digits in string
  809.  
  810. @@NewDigit:                               ; for each character
  811.    ZERO     dx                            ; dx:ax is dividend so make dx 0
  812.    div      bx                            ; ax = dx:ax / 10
  813.    push     dx                            ; dx = dx:ax mod 10
  814.    inc      cl                            ; one more digit processed
  815.    or       ax, ax                        ; anything left?
  816.    jnz      @@NewDigit
  817.  
  818. @@NextChar:                               ; for each power of ten
  819.    pop      ax
  820.    add      al, '0'
  821.    mov      [BYTE PTR di], al
  822.    inc      di
  823.    loop     @@NextChar
  824.    mov      [BYTE PTR di], EOS            ; don't forget to end it!
  825.  
  826.    pop      di dx cx bx ax
  827.    ret
  828.  
  829. ENDP utoa
  830.  
  831.  
  832. EVEN
  833. ;-------------------------------------------------------------------------;
  834. ;  Purpose:    Converts character to lowercase.
  835. ;  Notes:      none
  836. ;  Requires:   8086-class CPU.
  837. ;  Entry:      AL = character to be converted.
  838. ;  Exit:       AL = converted character.
  839. ;  Calls:      none
  840. ;  Changes:    AL
  841. ;              flags
  842. ;-------------------------------------------------------------------------;
  843. PROC tolower
  844.  
  845.    cmp      al, 'A'                       ; if < 'A' then done
  846.    jb       SHORT @@Fin
  847.    cmp      al, 'Z'                       ; if > 'Z' then done
  848.    ja       SHORT @@Fin
  849.    or       al, 20h                       ; make it lowercase
  850. @@Fin:
  851.    ret
  852.  
  853. ENDP tolower
  854.  
  855.  
  856. ;-------------------------------------------------------------------------;
  857. ;  Purpose:    Converts character to uppercase.
  858. ;  Notes:      none
  859. ;  Requires:   8086-class CPU.
  860. ;  Entry:      AL = character to be converted.
  861. ;  Exit:       AL = converted character.
  862. ;  Calls:      none
  863. ;  Changes:    AL
  864. ;              flags
  865. ;-------------------------------------------------------------------------;
  866. PROC toupper
  867.  
  868.    cmp      al, 'a'                       ; if < 'a' then done
  869.    jb       SHORT @@Fin
  870.    cmp      al, 'z'                       ; if > 'z' then done
  871.    ja       SHORT @@Fin
  872.    and      al, not 20h                   ; make it uppercase
  873. @@Fin:
  874.    ret
  875.  
  876. ENDP toupper
  877.  
  878.  
  879. EVEN
  880. ;-------------------------------------------------------------------------;
  881. ;  Purpose:    Calculates length of an ASCIIZ string.
  882. ;  Notes:      Terminal char is _not_ included in the count.
  883. ;  Requires:   8086-class CPU.
  884. ;  Entry:      ES:DI = pointer to string.
  885. ;  Exit:       CX = length of string,
  886. ;              cf = 0 and zf = 1 if EOS found,
  887. ;              cf = 1 and zf = 0 if EOS not found within segment.
  888. ;  Calls:      none
  889. ;  Changes:    CX,
  890. ;              flags
  891. ;-------------------------------------------------------------------------;
  892. PROC strlen
  893.  
  894.    push     ax di
  895.    pushf
  896.    cld                                    ; scan forward only
  897.    mov      al, EOS                       ; character to search for
  898.    mov      cx, di                        ; where are we now
  899.    not      cx                            ; what's left in segment - 1
  900.    push     cx                            ; save char count
  901.    repne    scasb
  902.    je       SHORT @@Done
  903.    scasb                                  ; test final char
  904.    dec      cx                            ; avoids trouble with "not" below
  905.  
  906. @@Done:
  907.    pop      ax                            ; get original count
  908.    sub      cx, ax                        ; subtract current count
  909.    not      cx                            ; and invert it
  910.    popf                                   ; restore df
  911.    dec      di
  912.    cmp      [BYTE PTR es:di], EOS
  913.    je       SHORT @@Fin                   ; cf = 0 if equal
  914.    stc                                    ; set cf => error
  915.  
  916. @@Fin:
  917.    pop      di ax
  918.    ret
  919.  
  920. ENDP strlen
  921.  
  922.  
  923. END
  924.